package webServices;

import image.Image;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.swing.JFrame;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;

import photoshop.Photoshop;

import user.UserDataBase;
import basicShapes.Arc;
import basicShapes.Ellipse;
import basicShapes.Line;
import basicShapes.Point;
import basicShapes.Polygon;
import basicShapes.Rectangle;

@WebService(name="metaphotoshop", targetNamespace="http://metaphotoshop/")
public class MetaDraw {
	
	HashMap<Object, Integer> webServicesList = new HashMap<Object, Integer>();
	HashMap<String, Object> userBinding = new HashMap<String, Object>();
	Photoshop p;
	int loadLimit = 4;
	
	public MetaDraw() {

	}
	
	@WebMethod(exclude=true)
	public void addWS(String url) {
		photoshop.DrawService ds;
		try {
			ds = new photoshop.DrawService(new URL(url+"?WSDL"), new QName("http://photoshop/", "DrawService"));
			webServicesList.put(ds.getPhotoshopPort(), 0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@WebMethod(exclude=true)
	public Photoshop selectWS(String id) {
		if(webServicesList.isEmpty()) System.out.println("AUCUN SERVEUR N'EST DISPONIBLE !");
		if(userBinding.containsKey(id)) {
			try {
				if(((Photoshop) userBinding.get(id)).ping() == true) {
					return (Photoshop) userBinding.get(id);
				}
			}catch(Exception e) {
				System.out.println("Recover from server crash ...");
				webServicesList.remove(userBinding.get(id));
				userBinding.remove(id);
				System.out.println("... Done !");
			}
		}
		int minUsers = Integer.MAX_VALUE;
		for(Object p : webServicesList.keySet()) {
			if (webServicesList.get(p) < loadLimit && webServicesList.get(p) < minUsers) {
				minUsers = webServicesList.get(p);
			}
		}
		for(Object p : webServicesList.keySet()) {
			if (webServicesList.get(p) == minUsers) {
				webServicesList.put(p, webServicesList.get(p)+1);
				userBinding.put(id, p);
				System.out.println("--info : User "+id+" will use the service: "+p);
				System.out.print("root@server:");
				return (Photoshop) p;
			}
		}
		return null;
	}
	
	@WebMethod(operationName="logIn")
	public Boolean logIn(String login) {
		return UserDataBase.getInstance().isAccessGranted(login);
	}
	
	@WebMethod(operationName="logOut")
	public int logOut(String login) {
		p = ((Photoshop) selectWS(login));
		webServicesList.put(p, webServicesList.get(p)-1);
		userBinding.remove(login);
		System.out.println("\n--info : User '"+login+"' has logged out");
		System.out.print("root@server:");
		return JFrame.EXIT_ON_CLOSE;
	}
	
	@WebMethod(operationName="getMyImagesName")
	public ArrayList<String> getMyImagesName(String login) {
		p = ((Photoshop) selectWS(login));		
		if(isGrantedUser(login, "getAllImagesName", null, null)) {
			return (ArrayList<String>) p.getAllImagesName();
		}
		else {
			return (ArrayList<String>) p.getMyImagesName(login);
		}
	}
	
	@WebMethod(operationName="isGrantedUser")
	public Boolean isGrantedUser(String user, String action, String image, String image2) {
		if(image == null && image2 == null) {
        	return UserDataBase.getInstance().isAccessGranted(user, action, null, null);
        }
		else if(image2 == null) {
			return UserDataBase.getInstance().isAccessGranted(user, action, unmarshaliseImage(image), null);
		}
		else {
			return UserDataBase.getInstance().isAccessGranted(user, action, unmarshaliseImage(image), unmarshaliseImage(image2));
		}
	}
	
	@WebMethod(operationName="getImageShapes")
	public ArrayList<String> getImageShapes(String id,String file){
		p = ((Photoshop) selectWS(id));
		return (ArrayList<String>) p.getImageShapes(file);
	}
	
	@WebMethod(operationName="createImage")
	public void createImage(String name, String owner) {
		p = ((Photoshop) selectWS(owner));
		p.createImage(name, owner);
	}
	
	@WebMethod(operationName="addArc")
	public void addArc(String id, String file, int x, int y, int w, int h, int s, int e, int t) {
		p = ((Photoshop) selectWS(id));
		p.addArc(file, x, y, w, h, s, e, t);
	}
	
	@WebMethod(operationName="addEllipse")
	public void addEllipse(String id, String file, int x, int y, int w, int h) {
		p = ((Photoshop) selectWS(id));
		p.addEllipse(file, x, y, w, h);
	}
	
	@WebMethod(operationName="addLine")
	public void addLine(String id, String file, int x1, int y1, int x2, int y2) {
		p = ((Photoshop) selectWS(id));
		p.addLine(file, x1, y1, x2, y2);
	}
	
	@WebMethod(operationName="addPolygon")
	public void addPolygon(String id, String file, ArrayList<Integer> pointsX, ArrayList<Integer> pointsY, int size) {
		p = ((Photoshop) selectWS(id));
		p.addPolygon(file, pointsX, pointsY, size);
	}
	
	@WebMethod(operationName="addRectangle")
	public void addRectangle(String id, String file, int x, int y, int w, int h) {
		p = ((Photoshop) selectWS(id));
		p.addRectangle(file, x, y, w, h);
	}
	
	@WebMethod(operationName="addImage")
	public void addImage(String id, String file_dest, String new_file) {
		p = ((Photoshop) selectWS(id));
		p.addImage(file_dest, new_file);
	}
	
	@WebMethod(operationName="getXML")
	public String getXML(String id, String image) {
		p = ((Photoshop) selectWS(id));
		return p.getXML(image);
	}
	
	public static Image unmarshaliseImage(String file) {
		try {
			/* UNMARSHALLER XML TO JAVA */
			JAXBContext context = JAXBContext.newInstance(Image.class, 
															Line.class,
															Ellipse.class,
															Arc.class,
															Polygon.class,
															Rectangle.class,
															Point.class);
			Unmarshaller u = context.createUnmarshaller();
			Image i_lue = (Image) u.unmarshal(new File(file+".xml"));
			return i_lue;
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public void marshaliseImage(Image i) {
		try {
			/* MARSHALLER JAVA TO XML */
			JAXBContext context = JAXBContext.newInstance(Image.class, 
															Line.class,
															Ellipse.class,
															Arc.class,
															Polygon.class,
															Rectangle.class,
															Point.class);
			Marshaller m = context.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			m.marshal(i, new File(i.getName()+".xml"));
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	@WebMethod(operationName="getImagePng")
	public byte[] getImagePng(String id, String image) {
		p = ((Photoshop) selectWS(id));
		return p.getImagePng(image);
	}
	
	@WebMethod(operationName="removeItem")
	public void removeItem(String id, String image, String item_to_be_removed) {
		p = ((Photoshop) selectWS(id));
		p.removeItem(image, item_to_be_removed);
	}
	
	@WebMethod(operationName="deleteItem")
	public void deleteItem(String id, String image) {
		p = ((Photoshop) selectWS(id));
		p.deleteItem(image);
	}

	public HashMap<Object, Integer> getWebServicesList() {
		return webServicesList;
	}

	public int getLoadLimit() {
		return loadLimit;
	}
}
